#ifndef PROCESS_H_
#define PROCESS_H_

#include <types.h>

#define	STATE_UNUSED 0
#define	STATE_READY 1
#define	STATE_RUNNING 2
#define	STATE_SLEEPING 3
#define	STATE_KILLED 4
#define STATE_BLOCKED 5

#define QUANTUM_MAX 255
#define QUANTUM_MIN 1
// TODO: adjust this qemu has bad timer support
#define QUANTUM_STD 10

#define PRIORITY_MIN 1
#define PRIORITY_STD 2
#define PRIORITY_MAX (PRIORITY_STD+1)
#define PRIORITIES PRIORITY_MAX

#define STACKSIZE 0x1000

#define	REG(p,r)	((p)->context->r)
#define DEFAULT_EFLAGS ((1 << 1) | (1 << 9))

typedef struct context
{
	// pushed manually
	dword ss;
	dword gs;
	dword fs;
	dword es;
	dword ds;
	
	// pushed by pusha
	dword edi;
	dword esi;
	dword ebp;
	dword esp;
	dword ebx;
	dword edx;
	dword ecx;
	dword eax;
	
	// pushed by interrupt usually 
	dword vector;
	dword code;
	dword eip;
	dword cs;
	dword eflags;
} context_t;

typedef dword stack_t[STACKSIZE / sizeof(dword)];

struct thread;

typedef struct process
{
	struct thread *threads;
	struct process *next_process;
	struct process *prev_process;
	dword *pd;
	word pid;
	word state;
	byte user;  /* owner */
} process_t;

typedef struct thread
{
	/* four-byte fields */
	context_t *context;  /* saved process registers etc. */
	stack_t *stack;  /* location of the process stack */
	process_t *process;
	struct thread *next_sibling;  // may not need these...
	struct thread *prev_sibling;
	struct thread *next_thread;
	struct thread *prev_thread;
	/* two-byte fields */
	word state;  /* current state */
	word tid;  /* identity */
	/* one-byte fields */
	byte quantum;  /* typical time slice for this process */
	byte priority;  /* determines how the process is scheduled */
} __attribute__((packed)) thread_t;

//extern word next_pid;

extern stack_t *g_isr_stack_ptr;
extern stack_t g_system_stack;

int init_processes(void);
void proc_destroy_thread(thread_t *thread);
thread_t * proc_create_thread(process_t *parent, dword *entry);
process_t * proc_create_process(dword *entry);
thread_t * proc_get_systhread(void);
process_t * proc_get_sysprocess(void);
byte proc_get_next_pid(void);
byte proc_get_next_tid(void);

#endif /*PROCESS_H_*/
